// 网络请求的模块
import axios from 'axios'
// 从 Vant 组件库中，按需导入 Toast 组件
import { Toast } from 'vant'
// 导入 store 模块
import store from '@/store/index.js'
// 导入大数处理的模块
import bigInt from 'json-bigint'
// 按需导入换取 token 的 API 接口
import { exchangeTokenAPI } from '@/api/userAPI.js'
// 导入路由模块
import router from '@/router/index.js'

// 定义一个中间件函数，形参中的 data 就是服务器响应回来的，原装的数据
const trasnBigInt = (data) => {
  if (!data) return ''

  // TODO：在这里对大数进行转换
  // 注意：大数处理的结果：超范围的数字变成了 BigNumber 对象了
  return bigInt.parse(data)
}

// 创建 axios 的实例
const instance = axios.create({
  // 请求的根路径
  baseURL: 'http://toutiao-app.itheima.net',
  // 通过 transformResponse 来指定处理数据的中间件  {{ article.pubdate | A | B | C }}
  transformResponse: [trasnBigInt]
})

// 添加请求拦截器
// 注意：把官方文档的代码复制过来以后，一定要把 axios.interceptors 替换为 instance.interceptors
instance.interceptors.request.use(function(config) {
  // 在发送请求之前做些什么
  // 在请求拦截器中，展示 loading 效果
  Toast.loading({
    message: '加载中...',
    duration: 0 // 如果 duration 的值为 0，则 loading 效果不会自动关闭
  })

  // 获取 token 字符串的值
  // store.state.tokenInfo 对象中包含以下两个属性 { token, refresh_token }
  const tokenStr = store.state.tokenInfo.token
  // 如果 tokenStr 不为空，则添加 Authorization 认证字段
  if (tokenStr) {
    config.headers.Authorization = 'Bearer ' + tokenStr
  }

  return config
}, function(error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

// 添加响应拦截器
instance.interceptors.response.use(function(response) {
  // 对响应数据做点什么
  // 在响应拦截器中隐藏 loading 效果
  Toast.clear()

  return response
}, async function(error) {
  // 对响应错误做点什么
  // 如果接口调用失败，也需要隐藏 loading 效果
  Toast.clear()

  // 从 vuex 中获取到 tokenInfo 这个对象，格式为 { token, refresh_token }
  const tokenInfo = store.state.tokenInfo
  // 判断是否为 token 过期导致的请求失败
  if (error.response && error.response.status === 401 && tokenInfo.refresh_token) {
    // 进行换取 token 的操作
    console.log('进行换取 token 的操作')
    try {
      const { data: res } = await exchangeTokenAPI(tokenInfo.refresh_token)
      if (res.message === 'OK') {
      // 换取 token 成功了
        console.log('新token的值是：', res.data.token)
        // 更新 vuex 中 token 的值
        store.commit('updateTokenInfo', { token: res.data.token, refresh_token: tokenInfo.refresh_token })

        console.dir(error)
        // 在第二个 function 中，return 了一个请求的 Promise 对象
        // 注意：这一行代码我们只能分析过程，但是没有为什么（因为这是 axios 官方提供的用法）
        return instance(error.config)
      }
    } catch {
      // 如果能够进入到 catch 中执行，就证明 token 和 refresh_token 都过期了！！！
      // 1. 清空 vuex 和 localStorage
      store.commit('cleanState')
      // 2. 强制跳转到登录页
      router.push('/login?pre=' + router.currentRoute.fullPath)
    }
  }

  return Promise.reject(error)
})

// 向外共享 axios 的实例
export default instance
